module mculib.arm.gpio;
/**
* 通用GPIO模块
*History: 
*   2023-02-01, 独立Pin功能基本实现
*/
import mculib.chip;


final abstract class DGPIO
{
    
}



version(None):
import arm.misc;
import arm.rcc;
import arm.utils;



//pragma(msg,"661:",HasPeriph!(Peripherals.GPIOA.stringof));
//pragma(msg,"66:",__traits(hasMember, Peripherals, Peripherals.GPIOA.stringof));
//pragma(msg,"55:", typeof(Peripherals.DBG.DBGMCU_CR));
//pragma(msg, __traits(getAttributes, Peripherals.DBG.DBGMCU_CR));
/**
* 判定是否有GPIO外设
*/
private enum bool hasBusPeriph = HasPeriph!("GPIOA","GPIOB","GPIOC","GPIOD","GPIOE","GPIOF","GPIOG","GPIOH");

static if(hasBusPeriph):
//import core.volatile;
import arm.volatile;
import arm.bus;


/// 端口编号对应字符串
private enum PinTable = [
    0:"0",
    1:"1",
    2:"2",
    3:"3",
    4:"4",
    5:"5",
    6:"6",
    7:"7",
    8:"8",
    9:"9",
    10:"10",
    11:"11",
    12:"12",
    13:"13",
    14:"14",
    15:"15",
    ];

/// 引脚模式
enum PinModer :ubyte
{
    input           = 0b00,     /// 输入
    output          = 0b01,     /// 输出
    alternate       = 0b10,     /// 复用
    analog          = 0b11,     /// 模拟
}

/// 配置引脚输出类型
enum PinOTyper :bool
{
    pushPull        = false,     /// 推挽
    openDrain       = true,     /// 开漏
}
/// 硬件输出速度
enum PinOSpeedr :ubyte 
{
    low             = 0b00,     /// 低速, 2MHz
    medium          = 0b01,     /// 中速, 12.5MHz ~ 50MHz
    high            = 0b10,     /// 高速, 25MHz ~ 100MHz
    veryHigh        = 0b11,     /// 超高速, 50MHz ~ 200MHz
}
/// 电平补偿
enum PinPUPDR  :ubyte
{
    none            = 0b00,     /// 无上拉下拉
    pullUp          = 0b01,     /// 上拉
    pullDown        = 0b10,     /// 下拉
    Reserved        = 0b11,     /// 保留
}
/// 备用功能
enum PinAlternate :ubyte
{
    AF0             = 0b0000,   /// 备用功能0
    AF1             = 0b0001,   /// 备用功能1
    AF2             = 0b0010,   /// 备用功能2
    AF3             = 0b0011,   /// 备用功能3
    AF4             = 0b0100,   /// 备用功能4
    AF5             = 0b0101,   /// 备用功能5
    AF6             = 0b0110,   /// 备用功能6
    AF7             = 0b0111,   /// 备用功能7
    AF8             = 0b1000,   /// 备用功能8
    AF9             = 0b1001,   /// 备用功能9
    AF10            = 0b1010,   /// 备用功能10
    AF11            = 0b1011,   /// 备用功能11
    AF12            = 0b1100,   /// 备用功能12
    AF13            = 0b1101,   /// 备用功能13
    AF14            = 0b1110,   /// 备用功能14
    AF15            = 0b1111,   /// 备用功能15
}

/// 端口掩码, 16位对应16个引脚
enum PortMask : ushort
{
    Pin0 = 1 << 0,
    Pin1 = 1 << 1,
    Pin2 = 1 << 2,
    Pin3 = 1 << 3,
    Pin4 = 1 << 4,
    Pin5 = 1 << 5,
    Pin6 = 1 << 6,
    Pin7 = 1 << 7,
    Pin8 = 1 << 8,
    Pin9 = 1 << 9,
    Pin10 = 1 << 10,
    Pin11 = 1 << 11,
    Pin12 = 1 << 12,
    Pin13 = 1 << 13,
    Pin14 = 1 << 14,
    Pin15 = 1 << 15,
    PortNull = 0,
    PortAll = ushort.max,

}
/**
* GPIO初始化结构
*/
struct GPIO_InitTypeDef
{
    immutable(ushort)          pin;        /// 引脚 0 ~ 15
    /// 模式
    PinModer        moder;
    /// 输出类型
    PinOTyper       otyper;
    /// 输出速度
    PinOSpeedr      ospeedr;
    /// 上拉下拉
    PinPUPDR        pupdr;
    /// 复用功能
    ubyte            alternate;
}


/**
* GPIO端口操作模板
*Params: 
*   Peripheral = 总线接口
*   PortMask = 端口掩码, 16位对应16个引脚
*/
static interface GPIO(alias mPeri,uint mPortMask = PortMask.PortNull )
//if( HasPeriph!(mBase.stringof) && (mPeriMask > 0))
{
    import core.bitop:bsf,bsr;

    enum IFName = __traits(identifier, mPeri);
    version(None) enum GPIOA_Type* mBase = Peripherals.GPIOA;
    else enum mBase = mPeri;


    private{
        /// 端口引脚最大数量
        //enum GPIO_Number = 16;
        enum mPortMask_HPOS = mPortMask ? bsr(mPortMask) : 0;
        enum mPortMask_LPOS = mPortMask ? bsf(mPortMask) : 0;

        
    }
    /**
    * 单端口引脚操作模板
    * Params:
    *   pin = 端口号
    */
    static interface Pin(int mPin) if((mPin < 16) && (mPin >= 0)) //: MMIOBus!(mPeri)
    {
        import arm.bitband:BitBand;
        
        enum IsPin = true;
        enum PinMask = 1u << mPin;
        enum BitBand_Set = BitBand!(cast(size_t)&mBase.BSRR,mPin);
        enum BitBand_Clr = BitBand!(cast(size_t)&mBase.BSRR,mPin+16);

        static assert((mPortMask & PinMask),"Pin not exist");
        //enum Band_ODR = BitBand!(&mPeri.ODR,mPin);

        pragma(inline,_inline):
        /**
        * 读写电平到端口引脚
        * Params:
        *   level = 电平
        * Returns:
        *   当前电平
        */
        @property
        static void PinRW(bool Level)
        {
            auto nval = (1 << mPin) << (Level ? 0 : 16);
            //(&mPeri.BSRR).volatileStore(nval);
            mBase.BSRR = nval;
        }
        
        @property
        static bool PinRW()
        {
            enum mask = ReadMask!(mBase.mask_IDR,"IDR",PinTable[mPin]);
            //return mPeri.IDR.BitField!(mask) != 0;
            //return MMIO_Bitfield!("IDR",combineStr!("IDR",PinSet[mPin])) != 0;
            return mBase.IDR.opDispatch!(combineStr!("IDR",PinTable[mPin])) != 0;
        }
        /**
        * 设置端口引脚模式
        * Params: 
        *   mode = 模式, 详见 $(D PinModer) 
        */
        @property
        static void PinMode(PinModer mode)
        {
            mBase.MODER.opDispatch!(combineStr!("MODER",PinTable[mPin])) = mode;
        }
        @property
        static PinModer PinMode()
        {
            enum mask = ReadMask!(mBase.mask_MODER,"MODER",PinTable[mPin]);
            //return cast(PinModer)mPeri.MODER.BitField!(mask)();
            //return cast(PinModer)MMIO_Bitfield!("MODER",combineStr!("MODER",PinSet[mPin]))();
            return cast(PinModer) mBase.MODER.opDispatch!(combineStr!("MODER",PinTable[mPin]))();
        }
        /**
        * 设置端口引脚输出类型
        * Params:
        *   type = 输出类型, 详见 $(D PinOTyper)
        */
        @property
        static void PinType(PinOTyper type)
        {
            enum mask = ReadMask!(mBase.mask_OTYPER,"OT",PinTable[mPin]);
            //mPeri.OTYPER.BitField!(mask)(type);
            //MMIO_Bitfield!("OTYPER",combineStr!("OT",PinSet[mPin]),uint)(type);
            mBase.OTYPER.opDispatch!(combineStr!("OT",PinTable[mPin])) = type;
        }
        @property
        static PinOTyper PinType()
        {
            enum mask = ReadMask!(mBase.mask_OTYPER,"OT",PinTable[mPin]);
            //return cast(PinOTyper)mPeri.OTYPER.BitField!(mask)();
            //return cast(PinOTyper)MMIO_Bitfield!("OTYPER",combineStr!("OT",PinSet[mPin]))();
            return cast(PinOTyper) mBase.OTYPER.opDispatch!(combineStr!("OT",PinTable[mPin]))();
        }
        /**
        * 设置端口引脚输出速度
        * Params: 
        *   speed = 输出速度, 详见 $(D PinOSpeedr)
        */
        @property
        static void PinSpeed(PinOSpeedr speed)
        {
            enum mask = ReadMask!(mBase.mask_OSPEEDR, "OSPEEDR",PinTable[mPin]);
            //mPeri.OSPEEDR.BitField!mask(speed);
            //MMIO_Bitfield!("OSPEEDR",combineStr!("OSPEEDR",PinSet[mPin]),uint)(speed);
            //mPeri.OSPEEDR.opDispatch!(combineStr!("OSPEEDR",PinSet[mPin])) = speed;
            mBase.OSPEEDR.opDispatch!(combineStr!("OSPEEDR",PinTable[mPin])) = speed;
        }
        @property
        static PinOSpeedr PinSpeed()
        {
            //enum mask = __traits(getMember, Peripherals.mask_OSPEEDR, "OSPEEDR"~PinSet[mPin]);
            enum mask = ReadMask!(mBase.mask_OSPEEDR, "OSPEEDR",PinTable[mPin]);
            //return cast(PinOSpeedr) (mPeri.OSPEEDR.BitField!mask());
            //return cast(PinOSpeedr) (MMIO_Bitfield!("OSPEEDR",combineStr!("OSPEEDR",PinSet[mPin]))());
            //return cast(PinOSpeedr) (mPeri.OSPEEDR.opDispatch!(combineStr!("OSPEEDR",PinSet[mPin]))());
            return cast(PinOSpeedr) mBase.OSPEEDR.opDispatch!(combineStr!("OSPEEDR",PinTable[mPin]))();
        }
        /**
        * 备用功能
        * Params: 
        *   alternate = 备用功能, 详见 $(D PinAlternate)
        */
        @property
        static void PinAlter(PinAlternate alternate)
        {
            static if(mPin < 8){
                enum mask = ReadMask!(mBase.mask_AFRL, "AFRL",PinTable[mPin]);
                //mPeri.AFRL.BitField!mask(alternate);
                //MMIO_Bitfield!("AFRL",combineStr!("AFRL",PinSet[mPin]),uint)(alternate);
                mBase.AFRL.opDispatch!(combineStr!("AFRL",PinTable[mPin])) = alternate;
            }else{

                enum mask = ReadMask!(mBase.mask_AFRH, "AFRH",PinTable[mPin]);
                //mPeri.AFRH.BitField!mask(alternate);
                //MMIO_Bitfield!("AFRH",combineStr!("AFRH",PinSet[mPin]),uint)(alternate);
                mBase.AFRH.opDispatch!(combineStr!("AFRH",PinTable[mPin])) = alternate;
            }
        }
        @property
        static PinAlternate PinAlter()
        {
            static if(mPin < 8){
                enum mask = ReadMask!(mBase.mask_AFRL, "AFRL",PinTable[mPin]);
                //return cast(PinAlternate) (mPeri.AFRL.BitField!mask());
                //return cast(PinAlternate) (MMIO_Bitfield!("AFRL",combineStr!("AFRL",PinSet[mPin]))());
                return cast(PinAlternate) mBase.AFRL.opDispatch!(combineStr!("AFRL",PinTable[mPin]))();
            }else{
                enum mask = ReadMask!(mBase.mask_AFRH, "AFRH",PinTable[mPin]);
                //return cast(PinAlternate) (mPeri.AFRH.BitField!mask());
                //return cast(PinAlternate) (MMIO_Bitfield!("AFRH",combineStr!("AFRH",PinSet[mPin]))());
                return cast(PinAlternate) mBase.AFRH.opDispatch!(combineStr!("AFRH",PinTable[mPin]))();
            }
        }
        /**
        * 锁定端口引脚配置参数
        * todo: 未实现
        */
        @property
        static bool PinLock()
        {
            /*
            mixin("Peripheral.LCKR.LCK"~PinSet[pin]~".val(1);");
            mixin("Peripheral.LCKR.LCK"~PinSet[pin]~".val(0);");
            mixin("Peripheral.LCKR.LCK"~PinSet[pin]~".val(1);");
            return mixin("Peripheral.LCKR.LCK"~PinSet[pin]~".val()");
            */
            return false;
        }
        /// 引脚电平上拉/下拉补偿设置
        @property
        static void PinPull(PinPUPDR pull)
        {
            mBase.PUPDR.opDispatch!(combineStr!("PUPDR",PinTable[mPin])) = pull;
        }
        /// 引脚位清除
        @property
        static void PinClr()
        {
            mBase.BSRR.opDispatch!(combineStr!("BR",PinTable[mPin])) = 1;
        }
        /// 引脚位设置
        @property
        static void PinSet()
        {
            mBase.BSRR.opDispatch!(combineStr!("BS",PinTable[mPin])) = 1;
        }
        /// 引脚位翻转
        @property
        pragma(inline,_inline)
        static void PinToggle()
        {
            mBase.ODR ^= PinMask;
        }

    }


    static if(mPortMask != 0)                           /// 仅当端口掩码中包含可操作引脚时才有效
    {
        /**
        * 读写端口
        * Params: 
        *   val = 写入值 位对应控制掩码 $(D PMask)
        * Returns:
        *   当前端口电平 位对应控制掩码 $(D PMask)
        * todo: 写入过程未实现原子操作
        */
        @property
        static void PortRW(ushort val)
        {
            //(&mPeri.ODR).volatileStore(val & mPeriMask);        
            mBase.ODR = val & mPortMask;
        }
        @property
        static ushort PortRW()
        {
            //return cast(ushort)((&mPeri.ODR).volatileLoad() & mPeriMask);
            return cast(ushort)(mBase.ODR & mPortMask);
        }
        /// 端口电平置位
        static void PortSet()
        {
            mBase.BSRR = mPortMask;
        }
        /// 端口电平位清除
        static void PortReset()
        {
            mBase.BSRR = mPortMask << 16;
        }
        /**
        * 端口电平翻转
        * 以对应IO口掩码范围内所有引脚电平翻转
        */
        static void PortToggle()
        {
            mBase.ODR ^= mPortMask;
        }

        /**
        * 端口设置模式涉及到端口掩码范围内所有引脚
        * Params:
        *   mode = 模式, 详见 $(D PinModer)
        */
        @property
        static void PortMode(PinModer mode)
        {
            static foreach(i;mPortMask_LPOS .. (mPortMask_HPOS+1)){
                static if(mPortMask & (1 << i)){
                    Pin!(i).PinMode = mode;
                }
            }
        }
        /**
        * 端口设置上拉下拉涉及到端口掩码范围内所有引脚
        */
        @property
        static void PortType(PinOTyper type)
        {
            static foreach(i;mPortMask_LPOS .. (mPortMask_HPOS+1)){
                static if(mPortMask & (1 << i)){
                    Pin!(i).PinType = type;
                }
            }
        }
        /**
        * 掩码涉及引脚IO的速度设置
        */
        @property
        static void PortSpeed(PinOSpeedr speed)
        {
            static foreach(i;mPortMask_LPOS .. (mPortMask_HPOS+1)){
                static if(mPortMask & (1 << i)){
                    Pin!(i).PinSpeed = speed;
                }
            }
        }
        /**
        * 端口功能复用涉及到端口掩码范围内所有引脚
        */
        @property
        static void PortAlter(PinAlternate alternate)
        {
            static foreach(i;mPortMask_LPOS .. (mPortMask_HPOS+1)){
                static if(mPortMask & (1 << i)){
                    Pin!(i).PinAlter = alternate;
                }
            }
        }
        /// 电平上拉/下拉补偿设置
        @property
        static void PortPull(PinPUPDR pull)
        {
            static foreach(i;mPortMask_LPOS .. (mPortMask_HPOS+1)){
                static if(mPortMask & (1 << i)){
                    Pin!(i).PinPull = pull;
                }
            }
        }

    }

    /// 使能端口时钟
    static void Enable()
    {
        RCC.Power!(combineStr!(IFName,"EN"))(1);
    }
    /// 禁用端口时钟
    static void Disable()
    {
        RCC.Power!(combineStr!(IFName,"EN"))(0);
    }
    /// 获取端口时钟状态
    static bool IsEnable()
    {
        
        return RCC.Power!(combineStr!(IFName,"EN"))() !=0;
    }

    /// 初始化端口
    static void InitGPIO(GPIO_InitTypeDef cfg)
    {
        //Peripheral
    }
    
    /**
    * 由端口掩码展开端口引脚操作模板
    */
    
    /*
    static foreach(i; 0 .. 16)
    {
        static if(mPeriMask & (1 << i))
        {
            mixin(`alias Pin`,PinSet[i],` = Pin!(`,PinSet[i],`);`);
        }
    }
    */

    
    
    

}



/// 独立IO端口操作用模板
/// alias fd1 = GPIO!(Peripherals.GPIOA,PortMask.PortAll);
//alias fd2 = fd1.Pin!(8);




//pragma(msg,__traits(allMembers, Peripherals.RCC.mask_AHB1ENR));

